#include "EntityGroup.h"
#include "Entity.h"

EntityGroup::EntityGroup() : AbstractEntity()
{

}

EntityGroup::EntityGroup( const Position& pos ) : AbstractEntity()
{
	setRelativePosition(pos);
}

void EntityGroup::preFrame( float frametime, const std::vector<Matrix4>& matrixes )
{
	AbstractEntity::preFrame(frametime, matrixes);

	// Relative verplaatsing tegenover parent
	m_matrixes.push_back( Transformation::getTranslationMatrix(getPosition()) );

	// Ga alle kinderen af
	std::vector<AbstractEntity*>::iterator it;
	for( it = m_children.begin(); it != m_children.end(); it++ )
	{
		AbstractEntity* child = *it;

		// Bounding size berekenen
		Dimensions childBoundingsize = child->getBoundingSize();
		m_boundingsize.x = MAX( m_boundingsize.x, fabs(child->getPosition().x + childBoundingsize.x)  );
		m_boundingsize.y = MAX( m_boundingsize.y, fabs(child->getPosition().y + childBoundingsize.y)  );
		m_boundingsize.z = MAX( m_boundingsize.z, fabs(child->getPosition().z + childBoundingsize.z) );

		child->preFrame(frametime, m_matrixes);

		// Voeg groep matrixen toe aan kind
		// Rotatie
		child->getMatrixes().push_back( Transformation::getTranslationMatrix(getAbsolutePosition() * -1 ));
		child->getMatrixes().push_back( Transformation::getRotationMatrix(getRotation()) );
		child->getMatrixes().push_back( Transformation::getTranslationMatrix(getAbsolutePosition()) );
	}
}

void EntityGroup::remove( AbstractEntity* ent )
{
	std::vector<AbstractEntity*>::iterator it = m_children.begin();
	while( it != m_children.end() )
	{
		if( (*it) == ent )
		{
			m_children.erase(it);
			ent->setParent(NULL);
		}
		else
			it++;
	}
}

void EntityGroup::add( AbstractEntity* ent )
{
	m_children.push_back(ent);
	ent->setParent( this );
}

void EntityGroup::postFrame()
{
	// Bereken resultaat van alle matrixes
	Matrix4 m;
	for( int j = 0; j < m_matrixes.size(); j++ )
	{
		m = m*m_matrixes[j];
	}
	m_matrixes.clear();

	// Bereken absolute position
	Vector middle(0,0,0);
	Transformation::apply(m, middle);
	setAbsolutePosition( middle );

	Vector boundingMax = INT_MIN;
	Vector boundingMin = INT_MAX;

	std::vector<AbstractEntity*>::iterator it;
	for( it = m_children.begin(); it != m_children.end(); it++ )
	{
		(*it)->postFrame();

		if( (*it)->isGroup() )
		{
			Vector boundingvol = (*it)->getAbsolutePosition() + (*it)->getBoundingSize() * 2;

			// Pak grootste waarde
			if(boundingvol.x >  boundingMax.x)
				boundingMax.x = boundingvol.x;
			if(boundingvol.y >  boundingMax.y)
				boundingMax.y = boundingvol.y;
			if(boundingvol.z >  boundingMax.z)
				boundingMax.z = boundingvol.z;

			// Pak kleinste waarde
			if(boundingvol.x <  boundingMin.x)
				boundingMin.x = boundingvol.x;
			if(boundingvol.y <  boundingMin.y)
				boundingMin.y = boundingvol.y;
			if(boundingvol.z <  boundingMin.z)
				boundingMin.z = boundingvol.z;
		}
		else
		{
			const std::vector<Position>& points = dynamic_cast<Entity*>(*it)->getPoints();

			for(int i = 0; i < points.size(); i++)
			{
				Position p = points[i];

				// Pak grootste waarde
				if(p.x >  boundingMax.x)
					boundingMax.x = p.x;
				if(p.y >  boundingMax.y)
					boundingMax.y = p.y;
				if(p.z >  boundingMax.z)
					boundingMax.z = p.z;

				// Pak kleinste waarde
				if(p.x <  boundingMin.x)
					boundingMin.x = p.x;
				if(p.y <  boundingMin.y)
					boundingMin.y = p.y;
				if(p.z <  boundingMin.z)
					boundingMin.z = p.z;
			}
		}
	}

	if( m_children.size() == 0 )
		m_boundingsize = 0;
	else
	{
		//m_boundingsize.x = fabs(boundingMax.x - boundingMin.x);
		//m_boundingsize.y = fabs(boundingMax.y - boundingMin.y);
		//m_boundingsize.z = fabs(boundingMax.z - boundingMin.z);
	}
}

void EntityGroup::frame( float frametime )
{
	std::vector<AbstractEntity*>::iterator it, it2;
	for( it = m_children.begin(); it != m_children.end(); it++ )
	{
		(*it)->frame(frametime);
	}
}

void EntityGroup::accept( AbstractVisitor* v )
{
	v->visit(this);
}

bool EntityGroup::hasCollision( AbstractEntity* other, bool doublechecked )
{
	if( !doublechecked && other->hasCollision( this, true ) )
		return true;

	//Broadphase

	//x-as vergelijken
	if(this->getAbsolutePosition().x + this->getBoundingSize().x > other->getAbsolutePosition().x + other->getBoundingSize().x && 
		other->getAbsolutePosition().x + other->getBoundingSize().x > this->getAbsolutePosition().x - this->getBoundingSize().x
		||
		this->getAbsolutePosition().x + this->getBoundingSize().x > other->getAbsolutePosition().x - other->getBoundingSize().x && 
		other->getAbsolutePosition().x - other->getBoundingSize().x > this->getAbsolutePosition().x - this->getBoundingSize().x)
	{}else{return false; }

	//y-as vergelijken
	if(this->getAbsolutePosition().y + this->getBoundingSize().y >= other->getAbsolutePosition().y + other->getBoundingSize().y && 
		other->getAbsolutePosition().y + other->getBoundingSize().y >= this->getAbsolutePosition().y - this->getBoundingSize().y
		||
		this->getAbsolutePosition().y + this->getBoundingSize().y >= other->getAbsolutePosition().y - other->getBoundingSize().y && 
		other->getAbsolutePosition().y - other->getBoundingSize().y >= this->getAbsolutePosition().y - this->getBoundingSize().y)
	{}else{return false; }

	return true;
}

void EntityGroup::checkCollision( AbstractEntity* other )
{
	if( hasCollision( other ) || other->hasCollision( this ) )
	{
		std::vector<AbstractEntity*>::iterator it, it2;
		for( it = m_children.begin(); it != m_children.end(); it++ )
		{
			(*it)->checkCollision( other );
		}
	}
}